//
//  CPMediaDecryptTool.m
//  CPSecurityTools
//
//  Created by collegepre on 16/7/4.
//  Copyright © 2016年 collegepre. All rights reserved.
//

#import "CPMediaDecryptTool.h"
#import "NSData+AES.h"
#import "GTMBase64.h"
#import <CommonCrypto/CommonCryptor.h>

// 视频加解密Key
static  NSString * const CPMediaDeCodeAESKEY = @"3A5C6A538BA2EC718FB63228A7D783B7";

@interface CPMediaDecryptTool()

@property (copy,nonatomic) CPDecryptMediaFileProgressBlock progressBlock;
@property (copy,nonatomic) CPDecryptMediaFileComplitionBlock complitionBlock;

@property (copy,nonatomic) CPDecryptMediaFileComplitionBlock singleComplitionBlock;

// 接收数据的Data
@property (nonatomic, strong) NSData *readData;

// 文件长度
@property (nonatomic, assign,readonly) NSInteger  fileLength;

// 当前解密的文件长度
@property (nonatomic, assign) NSInteger  currnentLength;

// 线程控制
@property (nonatomic, strong) NSOperationQueue *oprationQ;

@end


@implementation CPMediaDecryptTool

- (NSOperationQueue *)oprationQ{
    if (!_oprationQ) {
        _oprationQ = [[NSOperationQueue alloc] init];
        _oprationQ.maxConcurrentOperationCount = 2;
    }
    return _oprationQ;
}


+ (instancetype)defaultDecryptTool{
    CPMediaDecryptTool *tool =  [[CPMediaDecryptTool alloc] init];
    
    tool.currnentLength = 0;
    tool.readData = [NSData data];
    return tool;
}

/**
 *  用加密的header和Code解密视/音频文件
 *
 *  @param filePath   解密路径
 *  @param header     加密头位数
 *  @param key        加密Key
 *  @param progress   进度
 *  @param complition 完成
 */
- (void)decodeWithsuperFilePath:(NSString *)filePath
               headerCodeLength:(NSString *)header
                   keyCodeValue:(NSString *)key
                       progress:(CPDecryptMediaFileProgressBlock)prog
                     complition:(CPDecryptMediaFileComplitionBlock)complition{
    
    if (!header || [header isEqualToString:@"0"] || !key || [key isEqualToString:@"0"]) {
        complition(nil);
    }else{
        NSData *data = [[NSData alloc] initWithBase64EncodedString:header options:NSDataBase64DecodingIgnoreUnknownCharacters];
        NSString *p1  = [data AES256DecryptWithKeyString:CPMediaDeCodeAESKEY];
        
        NSData *data1 = [[NSData alloc] initWithBase64EncodedString:key options:NSDataBase64DecodingIgnoreUnknownCharacters];
        NSString *p2  = [data1 AES256DecryptWithKeyString:CPMediaDeCodeAESKEY];
        
        if (p1 && p2) {
            [self decryptWithsuperFilePath:filePath headerLength:p1 keyValue:p2 progress:^(float progress) {
                prog(progress);
            } complition:^(NSError *error) {
                complition(error);
            }];
        }else{
            NSError *error = [NSError errorWithDomain:@"秘钥为空" code:101 userInfo:@{@"filePath":[filePath stringByAppendingPathComponent:filePath],@"Header":p1,@"Key":p2}];
            complition(error);
        }
    }
}

- (void)decodeWithsuperFilePath:(NSString *)filePath
             andLessonCourseDic:(NSDictionary *)dic
                           gkey:(NSString *)gkey
                       givValue:(NSString *)givValue
                       progress:(CPDecryptMediaFileProgressBlock)prog
                     complition:(CPDecryptMediaFileComplitionBlock)complition
{
    if (!gkey.length || !givValue.length) {
        complition(nil);
    } else {
        NSData *keyData = [GTMBase64 decodeString:gkey];
        NSData *ivData = [GTMBase64 decodeString:givValue];
        
        if (keyData && ivData) {
            [self decryptWithsuperFilePath:filePath andLessonCourseDic:dic keyData:keyData ivData:ivData andKeyString:gkey andIvString:givValue progress:^(float progress) {
                prog(progress);
            } complition:^(NSError *error) {
                complition(error);
            }];
        }else{
            NSError *error = [NSError errorWithDomain:@"秘钥为空" code:101 userInfo:@{@"filePath":[filePath stringByAppendingPathComponent:filePath],@"keyData":@(keyData.length),@"ivData":@(ivData.length)}];
            complition(error);
        }
    }
}

/**
 *  解密目录下所有的音视频文件
 *
 *  @param filePath   文件目录
 *  @param header     解密头
 *  @param key        解密码
 *  @param progress   进度block
 *  @param complition 完成调用的block
 */
- (void)decryptWithsuperFilePath:(NSString *)filePath headerLength:(NSString *)header keyValue:(NSString *)key progress:(CPDecryptMediaFileProgressBlock)progress complition:(CPDecryptMediaFileComplitionBlock)complition
{
    NSFileManager *manager = [NSFileManager defaultManager];
    NSArray *arr = [manager subpathsAtPath:filePath];
    NSMutableArray *temp = [NSMutableArray array];
    for (NSString *subPath in arr) {
        CPMediaDecryptType mediaType = [self mediaTypeWithFilePath:subPath];
        if (mediaType == CPMediaDecryptTypeMP3 ||
            mediaType == CPMediaDecryptTypeMP4 ||
            mediaType == CPMediaDecryptTypeAVI ||
            mediaType == CPMediaDecryptTypeOGG ||
            mediaType == CPMediaDecryptTypeWEBM) {
            NSString  *mediaPath = [filePath stringByAppendingPathComponent:subPath];
            [temp addObject:mediaPath];
        }
    }
    
    if (temp.count) {
        __block NSInteger successNum = 0;
        
        for (int i = 0;i < temp.count;i++)
        {
            NSString *mediaPath = temp[i];
            NSBlockOperation *opration = [NSBlockOperation blockOperationWithBlock:^{
            CPMediaDecryptType mediaType = [self mediaTypeWithFilePath:mediaPath];
                if (mediaType) {
                    BOOL isSuc = [self addDecryptFileWithMediaPath:mediaPath index:i header:header.integerValue key:key.integerValue];
//                    NSLog(@"解密--%d",isSuc);
                    if (isSuc) {
                        successNum++;
                        if (successNum == temp.count) {
                            NSError *error;
                            complition(error);
                        }else{
                            float pro = (float)successNum / temp.count;
                            progress(pro);
                        }
                    }else{
                        NSError *error = [NSError errorWithDomain:@"解密文件失败..." code:101 userInfo:@{@"filePath":[filePath stringByAppendingPathComponent:mediaPath]}];
                        complition(error);
                        return;
                    }
                }
            }];
            
            [self.oprationQ addOperation:opration];
        }
    }else{
        complition(nil);
    }
}


- (NSMutableArray *)isDecryptWith:(NSDictionary *)lessonCourseDic {
    NSMutableArray *decryptArr = [NSMutableArray array];
    NSArray *children = [lessonCourseDic objectForKey:@"children"];
    for (NSDictionary *dic in children) {
        NSDictionary *bundleDic = [dic objectForKey:@"bundle"];
        if (bundleDic) {
            NSDictionary *coreDic = [bundleDic objectForKey:@"core"];
            if (coreDic) {
                NSString *coreAddress = [coreDic objectForKey:@"address"];
                NSString *type = [[coreDic objectForKey:@"type"] lowercaseString];
                if ([type isEqualToString:@"audio"] ||
                    [type isEqualToString:@"video"]||[type isEqualToString:@"adobe_pdf"]
                    ) {
                    if ([coreAddress isKindOfClass:[NSString class]] && coreAddress.length) {
                        [decryptArr addObject:coreAddress];
                    }
                } else if ([type isEqualToString:@"image"]) {
                    if ([coreAddress isKindOfClass:[NSArray class]]) {
                        NSArray *coreImageAdd = (NSArray *)coreAddress;
                        for (NSString *imageAddress in coreImageAdd) {
                            [decryptArr addObject:imageAddress];
                        }
                    }
                }
            }
            NSArray *supports = [bundleDic objectForKey:@"supports"];
            for (NSDictionary *subSupport in supports) {
                NSString *supportAddress = [subSupport objectForKey:@"address"];
                NSString *type = [[subSupport objectForKey:@"type"] lowercaseString];
                if ([type isEqualToString:@"audio"] ||
                    [type isEqualToString:@"video"]||[type isEqualToString:@"adobe_pdf"]) {
                    if ([supportAddress isKindOfClass:[NSString class]] && supportAddress.length) {
                        [decryptArr addObject:supportAddress];
                    }
                } else if ([type isEqualToString:@"image"]) {
                    if ([supportAddress isKindOfClass:[NSArray class]]) {
                        NSArray *supportImageAdd = (NSArray *)supportAddress;
                        for (NSString *imageAddress in supportImageAdd) {
                            [decryptArr addObject:imageAddress];
                        }
                    }
                }
            }
        }
    }
    return decryptArr;
}


- (void)decryptWithsuperFilePath:(NSString *)filePath andLessonCourseDic:(NSDictionary *)dic keyData:(NSData *)keyData ivData:(NSData *)ivData andKeyString:(NSString *)keyString andIvString:(NSString *)ivString progress:(CPDecryptMediaFileProgressBlock)progress complition:(CPDecryptMediaFileComplitionBlock)complition {
    NSFileManager *manager = [NSFileManager defaultManager];
    NSArray *contents = [manager contentsOfDirectoryAtPath:filePath error:nil];
    NSMutableArray *temp = [NSMutableArray array];
    for (NSString *dirPath in contents) {
        NSString *subDirPath = [filePath stringByAppendingPathComponent:dirPath];
        NSArray *arr = [manager subpathsAtPath:subDirPath];
        NSMutableArray *decryptPaths = [self isDecryptWith:dic];
        // 目录下的所有文件
        for (NSString *subPath in arr) {
            // 判断是否有需要解密类型的文件
            CPMediaDecryptType type = [self mediaTypeWithFilePath:subPath];
            if (type != CPMediaDecryptTypeNone) {
                for (NSString *decryptPath in decryptPaths) {
                    
                        if ([subPath isEqualToString:decryptPath]) {
                            // 说明需要进行二次解密
                            NSString  *mediaPath = [subDirPath stringByAppendingPathComponent:subPath];
                            [temp addObject:mediaPath];
                        }
                    
                }
            }
        }
    }
    
    if (temp.count) {
        __block NSInteger successNum = 0;
        for (int i = 0;i < temp.count;i++) {
            NSString *mediaPath = temp[i];
            NSBlockOperation *opration = [NSBlockOperation blockOperationWithBlock:^{
                if ([self mediaTypeWithFilePath:mediaPath]) {
                    BOOL isSuc = [self addDecryptFileWithMediaPath:mediaPath index:i keyData:keyData ivData:ivData andKeyString:keyString andIvString:ivString];
//                    NSLog(@"解密--%d---mediaPath:%@",isSuc,mediaPath);
                    if (isSuc) {
                        successNum++;
                        float pro = (float)successNum / temp.count;
                        progress(pro);
                        if (successNum == temp.count) {
                            NSError *error;
                            complition(error);
                        }else{
                            float pro = (float)successNum / temp.count;
                            progress(pro);
                        }
                    }else{
                        NSError *error = [NSError errorWithDomain:@"解密文件失败..." code:101 userInfo:@{@"filePath":[filePath stringByAppendingPathComponent:mediaPath]}];
                        complition(error);
                        return;
                    }
                }
            }];
            [self.oprationQ addOperation:opration];
        }
    }else{
        complition(nil);
    }
}

/**
 *  解密视音频文件
 *
 *  @param mediaPath 视音频文件路径
 *  @param index     数组中文件路径下标
 *
 *  @return 是否解密成功
 */
- (BOOL)addDecryptFileWithMediaPath:(NSString *)mediaPath index:(NSInteger)index  header:(NSInteger)header key:(NSInteger)key{
    
    NSFileManager *manager = [NSFileManager defaultManager];
    
    NSString *subPath = mediaPath;
    // 文件类型
    NSString *pathExtension = [subPath pathExtension];
    
    // 视音频文件路径的前路径
    NSString *prePath = [subPath stringByDeletingLastPathComponent];
    
    // 当前文件名
    NSString *tempfilePath = [NSString stringWithFormat:@"%@/ios_temp_%ld.%@",prePath,index,pathExtension];
    [manager removeItemAtPath:tempfilePath error:nil];
    [manager createFileAtPath:tempfilePath contents:nil attributes:nil];
    
    // 创建读写FILE
    FILE *readFile;
    FILE *writeFile;
    readFile = fopen([subPath cStringUsingEncoding:NSUTF8StringEncoding], "rb+");
    writeFile = fopen([tempfilePath cStringUsingEncoding:NSUTF8StringEncoding], "a+");
    
    
    NSDictionary *attributes = [manager attributesOfItemAtPath:subPath error:nil];
    
    _fileLength = ((NSNumber *)[attributes objectForKey:@"NSFileSize"]).integerValue;
    
    int decodeKey = (int)key;
    if (self.fileLength > header) {
        self.currnentLength = header;
        BOOL isSuc =  decodeFile(readFile, self.fileLength, self.currnentLength, writeFile,decodeKey);
        if (isSuc) {
            if([manager removeItemAtPath:mediaPath error:nil]){
                isSuc =  [manager moveItemAtPath:tempfilePath toPath:mediaPath error:nil];
            }else{
                isSuc = NO;
            }
        }
        return isSuc;
    }else{
        return NO;
    }
}

- (BOOL)addDecryptFileWithMediaPath:(NSString *)mediaPath index:(NSInteger)index keyData:(NSData *)keyData ivData:(NSData *)ivData andKeyString:(NSString *)keyString andIvString:(NSString *)ivString {
    
    NSFileManager *manager = [NSFileManager defaultManager];
    
    NSString *subPath = mediaPath;
    // 文件类型
    NSString *pathExtension = [subPath pathExtension];
    
    // 视音频文件路径的前路径
    NSString *prePath = [subPath stringByDeletingLastPathComponent];
    
    // 当前文件名
    NSString *tempfilePath = [NSString stringWithFormat:@"%@/ios_temp_%ld.%@",prePath,index,pathExtension];
    [manager removeItemAtPath:tempfilePath error:nil];
    [manager createFileAtPath:tempfilePath contents:nil attributes:nil];
    
    // 创建读写FILE
    FILE *readFile;
    FILE *writeFile;
    readFile = fopen([subPath cStringUsingEncoding:NSUTF8StringEncoding], "rb+");
    writeFile = fopen([tempfilePath cStringUsingEncoding:NSUTF8StringEncoding], "a+");
    
    NSDictionary *attributes = [manager attributesOfItemAtPath:subPath error:nil];
    NSLog(@"资源解密：%@",mediaPath);
    
    _fileLength = ((NSNumber *)[attributes objectForKey:@"NSFileSize"]).integerValue;
    _currnentLength = 0;
    CPMediaDecryptType decryptType = [self mediaTypeWithFilePath:tempfilePath];
    BOOL isSuc = NO;
    if (decryptType == CPMediaDecryptTypeAVI || decryptType == CPMediaDecryptTypeMP4) {
        isSuc = decodeFile3(readFile, self.fileLength, self.currnentLength, writeFile, keyData, ivData, decryptType);
        if (isSuc) {
            NSLog(@"解密成功：%@",mediaPath);
            if([manager removeItemAtPath:mediaPath error:nil]){
                isSuc =  [manager moveItemAtPath:tempfilePath toPath:mediaPath error:nil];
            }else{
                 NSLog(@"解密失败：%@",mediaPath);
                isSuc = NO;
            }
        }
    } else {
        isSuc =  decodeFile2(readFile, self.fileLength, self.currnentLength, writeFile,keyData,ivData,decryptType);
        if (isSuc) {
            NSLog(@"解密成功：%@",mediaPath);
            if([manager removeItemAtPath:mediaPath error:nil]){
                isSuc =  [manager moveItemAtPath:tempfilePath toPath:mediaPath error:nil];
            }else{
                isSuc = NO;
                NSLog(@"解密失败：%@",mediaPath);
            }
        }
    }
    return isSuc;
}

/**
 *  C函数解密视频
 *
 *  @param file         待解密的文件File
 *  @param fileLength   文件长度
 *  @param currentLegth 当前解密的文件长度
 *  @param direcFile    目标存储目录
 */
BOOL decodeFile(FILE *file,long fileLength,long currentLegth,FILE *direcFile,int key){
    BOOL isSucessed = false;
    NSInteger readLength = 1024 * 1024 * 10;
    if (fileLength - currentLegth > readLength) {
        // 指针指向首字节
        //读取文件
        // 成功，返回0，失败返回-1
        int set = fseek(file, currentLegth, SEEK_SET);
        if (set == 0) {
            Byte *buffer = malloc(sizeof(Byte) * readLength);
            fread(buffer, readLength, sizeof(Byte), file);
            currentLegth += readLength;
            //设置读取位置
            
//            printf("递归-fseek--%d\n",set);
            for (int i = 0 ; i < readLength; i++) {
                *(buffer + i ) -= key;
            }
            
            size_t writedData =  fwrite(buffer, sizeof(Byte), readLength, direcFile);
            if (writedData == readLength) {
                isSucessed = YES;
            }else{
                isSucessed = NO;
            }
            free(buffer);
            if (isSucessed) {
                return  decodeFile(file, fileLength, currentLegth,direcFile,key);
            }else{
                return isSucessed;
            }
            // 递归
        }
    }else{
        if(fileLength - currentLegth  > 0){
            long length = fileLength - currentLegth;
            int set = fseek(file, currentLegth, SEEK_SET);
            if (set == 0) {
                Byte *buffer = malloc(sizeof(Byte) * length);
                
                fread(buffer, length, sizeof(Byte), file);
                
                currentLegth += length;
                //设置读取位置
                for (int i = 0 ; i < length; i++) {
                    *(buffer + i ) -= key;
                }
                
                size_t writedData = fwrite(buffer, sizeof(Byte), length, direcFile);
                
//                printf("最终-fseek--%d",set);
                if (writedData == length) {
                    isSucessed = YES;
                }else{
                    isSucessed = NO;
                }
                
                // 释放内存
                free(buffer);
                
                // 关闭文件
                fclose(file);
                fclose(direcFile);
                
            }
        }
    }
    return isSucessed;
}


BOOL decodeFile3(FILE *file,long fileLength,long currentLegth,FILE *direcFile,NSData *keyData,NSData *ivData,CPMediaDecryptType decryptType) {
    // 采用进一法 例如：加密文件是17.3M或17.8M则块数一定是18块
    long checkChunkCount = (fileLength + (1024*1024 - 1)) / (1024 * 1024);
    BOOL isSucessed = false;
    int chunkCount = 0;
    // 1.获取块的个数
    long offset = fileLength-sizeof(int);
    int set = fseek(file, offset, SEEK_SET);
    if (set == 0) {
        fread(&chunkCount, sizeof(int), 1, file);
    }
    if (checkChunkCount != chunkCount) {
        // 说明块数是正确的
        // 关闭文件
        fclose(file);
        fclose(direcFile);
        return isSucessed;
    }
    NSMutableArray *encryptedChunkLength = [NSMutableArray arrayWithCapacity:chunkCount];
    NSMutableArray *encryptedChunkPosition = [NSMutableArray arrayWithCapacity:chunkCount];
    NSMutableArray *sourceChunkLength = [NSMutableArray arrayWithCapacity:chunkCount];
    // 2.设置指针的位置--->加密文件的块的大小中(加密内容+Array[源文件块的大小]+Array[加密文件块的大小]+块数);
    // 2.1设置源文件块相关
    long sourceChunkLengthPosition = fileLength - sizeof(int) - chunkCount * sizeof(int) - chunkCount * sizeof(int);
    do {
        int sourceChunkLengthSet = fseek(file, sourceChunkLengthPosition, SEEK_SET);
        if (sourceChunkLengthSet == 0) {
            int chunkLength;
            fread(&chunkLength, sizeof(int), 1, file);
            [sourceChunkLength addObject:@(chunkLength)];
        }
        sourceChunkLengthPosition = ftell(file);
    } while (sourceChunkLengthPosition < fileLength - sizeof(int) - chunkCount * sizeof(int));
    
    // 2.2.设置加密块相关
    long encryptedPosition = fileLength - sizeof(int) - chunkCount * sizeof(int);
    long encryptedChunkOffset = 0;
    // 2.3.设置指针偏移量数组
    do {
        int chunkLengthSet = fseek(file, encryptedPosition, SEEK_SET);
        if (chunkLengthSet == 0) {
            int chunkLength;
            fread(&chunkLength, sizeof(int), 1, file);
            [encryptedChunkLength addObject:@(chunkLength)];
            [encryptedChunkPosition addObject:@(encryptedChunkOffset)];
            encryptedChunkOffset = encryptedChunkOffset + chunkLength;
        }
        encryptedPosition = ftell(file);
    } while (encryptedPosition < fileLength - sizeof(int));
    
    long sourceFileLength = 0;
    // 4.解密数据
    for (int i = 0; i < encryptedChunkPosition.count; i++)
    {
        NSInteger enOffset = [encryptedChunkPosition[i] integerValue];
        int encryptedSet = fseek(file, enOffset, SEEK_SET);
        if (encryptedSet == 0) {
            // 加密的缓冲数据
            long encryptLength = [encryptedChunkLength[i] integerValue];
            Byte *encryptBuffer = malloc(sizeof(Byte) * encryptLength);
            fread(encryptBuffer, encryptLength, 1, file);
            
            // 解密的缓冲数据
            long sourceLength = [sourceChunkLength[i] integerValue];
            sourceFileLength = sourceFileLength + sourceLength;
            size_t sourceBufferSize = (sourceLength + kCCBlockSize3DES)
            &~(kCCBlockSize3DES- 1);
            Byte *sourceBuffer = malloc(sizeof(Byte) * sourceBufferSize);
            size_t numBytesDecrypted = 0;
            CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                                  kCCAlgorithm3DES,
                                                  kCCOptionPKCS7Padding,
                                                  [keyData bytes],
                                                  kCCKeySize3DES,
                                                  [ivData bytes],
                                                  encryptBuffer,
                                                  encryptLength,
                                                  sourceBuffer,
                                                  sourceBufferSize,
                                                  &numBytesDecrypted);
            if(cryptStatus == kCCSuccess) {
                fwrite(sourceBuffer, sizeof(Byte), sourceLength, direcFile);
                if (i == encryptedChunkPosition.count-1) {
                    // 说明是最后一个
                    //将文件位置指针置于文件结尾
                    long size = 0;
                    fseek(direcFile,0,SEEK_END);
                    //得到当前位置与文件开始位置的字节偏移量。
                    size = ftell(direcFile);
                    if (size == sourceFileLength) {
                        isSucessed = true;
                    } else {
                        isSucessed = false;
                    }
                }
                free(encryptBuffer);
                free(sourceBuffer);
            } else {
                free(encryptBuffer);
                free(sourceBuffer);
            }
        }
    }
    // 关闭文件
    fclose(file);
    fclose(direcFile);
    return isSucessed;
}

BOOL decodeFile2(FILE *file,long fileLength,long currentLegth,FILE *direcFile,NSData *keyData,NSData *ivData,CPMediaDecryptType decryptType) {
    BOOL isSucessed = false;
    if (decryptType == CPMediaDecryptTypeMP4 || decryptType == CPMediaDecryptTypeAVI || decryptType == CPMediaDecryptTypeMP3) {
        // 说明是视频
        // 每次只读取1M的数据
        NSInteger readLength = 1024 * 1024;
        if (fileLength - currentLegth > readLength) {
            // 指针指向首字节
            // 读取文件
            // 成功，返回0，失败返回-1
            int set = fseek(file, currentLegth, SEEK_SET);
            if (set == 0) {
                Byte *buffer = malloc(sizeof(Byte) * readLength);
                fread(buffer, readLength, sizeof(Byte), file);
                currentLegth += readLength;
                //设置读取位置
                Byte *decodeBuffer = NULL;
//                printf("二次解密====递归-fseek--%d\n",set);
                size_t decodeBufferSize = (readLength + kCCBlockSize3DES)
                &~(kCCBlockSize3DES- 1);
                decodeBuffer = malloc(sizeof(Byte) * decodeBufferSize);
                memset((void*)decodeBuffer,0x0, decodeBufferSize);
                
                size_t numBytesDecrypted = 0;
                CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                                      kCCAlgorithm3DES,
                                                      kCCOptionPKCS7Padding,
                                                      [keyData bytes],
                                                      kCCKeySize3DES,
                                                      [ivData bytes],
                                                      buffer,
                                                      readLength,
                                                      decodeBuffer,
                                                      decodeBufferSize,
                                                      &numBytesDecrypted);
                if(cryptStatus == kCCSuccess) {
                    size_t writedData =  fwrite(decodeBuffer, sizeof(Byte), readLength, direcFile);
                    if (writedData == readLength) {
                        isSucessed = true;
                    } else {
                        isSucessed = false;
                    }
                    free(buffer);
                    free(decodeBuffer);
                    if (isSucessed) {
                        return  decodeFile2(file, fileLength, currentLegth,direcFile,keyData,ivData,decryptType);
                    }else{
                        return isSucessed;
                    }
                } else {
                    free(buffer);
                    free(decodeBuffer);
                }
            }
        } else {
            if (fileLength - currentLegth > 0) {
                long length = fileLength - currentLegth;
                int set = fseek(file, currentLegth, SEEK_SET);
                if (set == 0) {
                    Byte *buffer = malloc(sizeof(Byte) * length);
                    
                    fread(buffer, length, sizeof(Byte), file);
                    
                    currentLegth += length;
                    //设置读取位置
                    Byte *decodeBuffer = NULL;
                    size_t decodeBufferSize = (length + kCCBlockSize3DES)
                    &~(kCCBlockSize3DES- 1);
                    decodeBuffer = malloc(sizeof(Byte) * decodeBufferSize);
                    memset((void*)decodeBuffer,0x0, decodeBufferSize);
                    
                    size_t numBytesDecrypted = 0;
                    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                                          kCCAlgorithm3DES,
                                                          kCCOptionPKCS7Padding,
                                                          [keyData bytes],
                                                          kCCKeySize3DES,
                                                          [ivData bytes],
                                                          buffer, length,
                                                          decodeBuffer,
                                                          decodeBufferSize,
                                                          &numBytesDecrypted);
                    
                    if (cryptStatus == kCCSuccess) {
                        size_t writedData = fwrite(decodeBuffer, sizeof(Byte), length, direcFile);
//                        printf("二次解密=====最终-fseek--%d",set);
                        if (writedData == length) {
                            isSucessed = true;
                        } else {
                            isSucessed = false;
                        }
                    }
                    // 释放内存
                    free(buffer);
                    free(decodeBuffer);
                    // 关闭文件
                    fclose(file);
                    fclose(direcFile);
                }
            }
        }
    } else if (decryptType == CPMediaDecryptTypeJPG || decryptType == CPMediaDecryptTypePNG|| decryptType == CPMediaDecryptTypePDF) {
        int set = fseek(file, 0, SEEK_SET);
        if (set == 0) {
            Byte *buffer = malloc(sizeof(Byte) * fileLength);
            fread(buffer, fileLength, sizeof(Byte), file);
            size_t decodeBufferSize = fileLength;
            void *decodeBuffer = malloc(sizeof(Byte) * decodeBufferSize);
            size_t numBytesDecrypted = 0;
            CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                                  kCCAlgorithm3DES,
                                                  kCCOptionPKCS7Padding,
                                                  [keyData bytes],
                                                  kCCKeySize3DES,
                                                  [ivData bytes],
                                                  buffer,
                                                  fileLength,
                                                  decodeBuffer,
                                                  decodeBufferSize,
                                                  &numBytesDecrypted);
            
            if (cryptStatus == kCCSuccess) {
                size_t writedData = fwrite(decodeBuffer, sizeof(Byte), fileLength, direcFile);
//                printf("二次解密=====最终-fseek--%d",set);
                if (writedData == fileLength) {
                    isSucessed = true;
                } else {
                    isSucessed = false;
                }
            }
            // 释放内存
            free(buffer);
            free(decodeBuffer);
            // 关闭文件
            fclose(file);
            fclose(direcFile);
        }
    }
    return isSucessed;
}

/**
 *  解密当个文件的方法
 *
 *  @param filePath 单个文件的路径
 */
- (BOOL)decryptWithsubFilePath:(NSString *)filePath headerLength:(NSInteger)heder keyValue:(NSInteger)key{
    BOOL isSuccess = NO;
    if ([filePath hasSuffix:@".avi"]||[filePath hasSuffix:@".mp4"])
    {
        // 文件类型
        NSString *pathExtension = [filePath pathExtension];
        
        //        filePath = [filePath stringByDeletingPathExtension];
        
        NSString *currentName = [filePath lastPathComponent];
        filePath = [filePath stringByDeletingLastPathComponent];
        
        NSString *tempfilePath = [NSString stringWithFormat:@"%@/ios_temp.%@",filePath,pathExtension];
        filePath = [filePath stringByAppendingPathComponent:currentName];
        
        
        NSMutableData *data = [NSMutableData dataWithContentsOfFile:filePath];
        
        // 去除多余的头位置
        NSRange range = NSMakeRange(0, heder);
        [data replaceBytesInRange:range withBytes:NULL length:0];
        Byte *testByte = (Byte *)[data bytes];
        for(int i = 0 ;i < [data length]; i++ )
        {
            *(testByte + i) -= key;
        }
        
        isSuccess =  [data writeToFile:tempfilePath atomically:YES];
        if (isSuccess) {
            NSFileManager *fileManage = [NSFileManager defaultManager];
            BOOL isDelete =  [fileManage removeItemAtPath:filePath error:nil];
            if (isDelete) {
                isSuccess = [fileManage moveItemAtPath:tempfilePath toPath:filePath error:nil];
            }
        }
    }
    return isSuccess;
}


/**
 *  分段式解密视频目录
 *
 *  @param filePath 文件路径
 *  @param key      解密Key
 */
- (void)decryptMediaFilePieceWithFilePath:(NSString *)filePath header:(NSString *)header key:(NSString *)key complition:(CPDecryptMediaFileComplitionBlock)complition{
    
    if (complition) {
        self.singleComplitionBlock = ^(NSError *error){
            complition(error);
        };
    }
    complition = self.singleComplitionBlock;
    NSFileManager *manager = [NSFileManager defaultManager];
    NSDictionary *attributes = [manager attributesOfItemAtPath:filePath error:nil];
    
    //获取文件长度
    _fileLength = ((NSNumber *)[attributes objectForKey:@"NSFileSize"]).integerValue - header.integerValue;
    
    if (self.fileLength <= 0) {
        NSLog(@"文件字节数为空");
        return;
    }
    
    NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
    NSInteger readLength = 1024 * 1024 * 10;
    
    // 设置初始位置
    [fileHandle seekToFileOffset:42];
    
    // /Users/Wade/Library/Developer/CoreSimulator/Devices/A73C5ACF-81D4-46B9-A69B-F2830E90B2FB/data/Containers/Data/Application/972AACA2-9EF1-4ACD-B77C-984772D0E3D8/Documents/demo.mp4
    // 文件类型名  .mp4
    NSString *pathExtension = [filePath pathExtension];
    
    //filePath = [filePath stringByDeletingPathExtension];
    NSString *fileComponentPath = [filePath stringByDeletingLastPathComponent];
    
    NSString *directPath = [NSString stringWithFormat:@"%@/ios_temp.%@",fileComponentPath,pathExtension];;
    
    [manager removeItemAtPath:directPath error:nil];
    // 开始解密
    [manager createFileAtPath:directPath contents:nil attributes:nil];
    
    // 开始解密
    [self decodeDataWithFileHandle:fileHandle  readLength:readLength directPath:directPath filePath:filePath key:key];
}

/**
 *  视频文件递归解密
 *
 *  @param fileHandle   文件Hangle
 *  @param fileLength    文件长度
 *  @param currentLength 当前解密的长度
 *  @param readLength    每次解密的长度
 *  @param directPath   解密后目标目录
 */
- (void)decodeDataWithFileHandle:(NSFileHandle *)fileHandle readLength:(NSInteger)readLength directPath:(NSString *)directPath filePath:(NSString *)filePath key:(NSString *)key
{
    NSFileHandle *writeHandle =  [NSFileHandle fileHandleForWritingAtPath:directPath];
    if (self.fileLength - self.currnentLength >= readLength) {
        [fileHandle seekToFileOffset:self.currnentLength];
        self.currnentLength += readLength;
        NSData *data =  [fileHandle readDataOfLength:readLength];
        //        Byte *readByte1 = (Byte *)[data bytes];
        
        Byte *readByte = malloc(sizeof(Byte) * readLength);
        
        [data getBytes:readByte length:sizeof(Byte) * readLength];
        for(int i = 0 ;i < readLength; i++ )
        {
            *(readByte + i) -= key.integerValue;
        }
        
        NSData *deData = [NSData dataWithBytes:readByte length:readLength];
        
        [writeHandle seekToEndOfFile];
        [writeHandle writeData:deData];
        free(readByte);
        data = nil;
        deData = nil;
        // 递归
        [self decodeDataWithFileHandle:fileHandle readLength:readLength directPath:directPath filePath:filePath key:key];
        
    }else{
        NSFileManager *manger = [NSFileManager defaultManager];
        if (self.fileLength - self.currnentLength > 0) {
            [fileHandle seekToFileOffset:self.currnentLength];
            NSData *data =  [fileHandle readDataOfLength:self.fileLength - self.currnentLength];
            Byte *readByte = (Byte *)[data bytes];
            for(int i = 0 ;i < [data length]; i++ )
            {
                *(readByte + i) -= key.integerValue;
            }
            [writeHandle seekToEndOfFile];
            [writeHandle writeData:data];
            [writeHandle closeFile];
            [fileHandle closeFile];
            data = nil;
            [manger removeItemAtPath:filePath error:nil];
            
            BOOL isSuccess = [[NSFileManager defaultManager] moveItemAtPath:directPath toPath:filePath error:nil];
            NSError *error;
            if (isSuccess) {
                self.singleComplitionBlock(error);
            }else{
                error = [NSError errorWithDomain:@"替换文件失败" code:1001 userInfo:nil];
                self.singleComplitionBlock(error);
            }
            self.currnentLength = self.fileLength;
            
            
        }else{
            // 结束
            [writeHandle closeFile];
            [fileHandle closeFile];
            
            [manger removeItemAtPath:filePath error:nil];
            BOOL isSuccess = [manger moveItemAtPath:directPath toPath:filePath error:nil];
            NSError *error;
            if (isSuccess) {
                self.singleComplitionBlock(error);
            }else{
                error = [NSError errorWithDomain:@"替换文件失败" code:1001 userInfo:nil];
                self.singleComplitionBlock(error);
            }
            
        }
    }
}


/**
 *  根据文件路径判断媒体文件类型
 *
 *  @param filePath 文件路径
 *
 *  @return 媒体类型值
 */
- (CPMediaDecryptType)mediaTypeWithFilePath:(NSString *)filePath{
    if ([filePath hasSuffix:@".MP4"]||[filePath hasSuffix:@".mp4"]) {
        return CPMediaDecryptTypeMP4;
    } else if ([filePath hasSuffix:@".MP3"]||[filePath hasSuffix:@".mp3"]){
        return CPMediaDecryptTypeMP3;
    } else if ([filePath hasSuffix:@".AVI"]||[filePath hasSuffix:@".avi"]){
        return CPMediaDecryptTypeAVI;
    } else if ([filePath hasSuffix:@".PNG"] || [filePath hasSuffix:@".png"]) {
        return CPMediaDecryptTypePNG;
    } else if ([filePath hasSuffix:@".JPG"] || [filePath hasSuffix:@".jpg"]) {
        return CPMediaDecryptTypeJPG;
    } else if ([filePath hasSuffix:@".OGG"] || [filePath hasSuffix:@".ogg"]) {
        return CPMediaDecryptTypeOGG;
    } else if ([filePath hasSuffix:@".WEBM"] || [filePath hasSuffix:@".webm"]) {
        return CPMediaDecryptTypeWEBM;
    } else if ([filePath hasSuffix:@".pdf"] || [filePath hasSuffix:@".PDF"]) {
           return CPMediaDecryptTypePDF;
    }else {
        return CPMediaDecryptTypeNone;
    }
}



@end
